package org.fpp.sqlparse;

import cn.hutool.core.collection.CollUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @author pengpeng_fu@infinova.com.cn
 * @date 2023-12-25 10:27
 */
public interface IndexSerializable extends Serializable {
    /**
     * 获取索引
     * @return 索引
     */
    Integer getIndex();

    /**
     * 获取连个集合之间增量更新的对象
     * @param oldCollection oldCollection
     * @param newCollection newCollection
     * @return 增量更新的对象 key为原始对象 value为变更后的对象
     * @param <A>
     */
    static <A extends IndexSerializable> Map<OperationWrapper<A>,A> getChange(Collection<A> oldCollection, Collection<A> newCollection) {
        Map<Integer,A> source = Optional.ofNullable(oldCollection)
                .map(oc->oc
                        .stream()
                        .collect(Collectors.toMap(IndexSerializable::getIndex, s->s)))
                .orElseGet(Collections::emptyMap);
        Map<Integer,A> newSource = Optional.ofNullable(newCollection)
                .map(nc->nc.stream().collect(Collectors.toMap(IndexSerializable::getIndex, s->s)))
                .orElseGet(Collections::emptyMap);
        //取差集
        Collection<A> disjunction = CollUtil.disjunction(source.values(), newSource.values());
        Map<OperationWrapper<A>,A> result = new TreeMap<>(Comparator.comparingInt(oldObj -> oldObj.getObject().getIndex()));
        for (A a : disjunction) {
            Integer index = a.getIndex();
            if(source.containsKey(index)&&newSource.containsKey(index)){
                result.put(new OperationWrapper<>(Operation.UPDATE, source.get(index)), newSource.get(index));
            }else if(!source.containsKey(index)&&newSource.containsKey(index)){
                result.put(new OperationWrapper<>(Operation.INSERT, newSource.get(index)), newSource.get(index));
            }else if(source.containsKey(index)&&!newSource.containsKey(index)){
                result.put(new OperationWrapper<>(Operation.DELETE, source.get(index)), source.get(index));
            }
        }
        return result;
    }




    /**
     * 操作
     */
    enum Operation{
        INSERT,UPDATE,DELETE
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode
    @ToString
    class OperationWrapper<A>{
        private Operation operation;
        private A object;
    }
}
